/*******
// C1CFG1bits.BRP = Fosc/2 /2/(C1CFG1bits.SJW+1+C1CFG2bits.PRSEG+1+C1CFG2bits.SEG1PH+1+C1CFG2bits.SEG2PH+1) -1
// 限制：
// 1、同步段+传播时间段+相位缓冲段1+相位缓冲段2 在8TQ到15TQ之间，包括边界值
// 2、传播时间段+相位缓冲段1 >= 相位缓冲段2
// 3、相位缓冲段2 > 同步段
C1CFG2bits.WAKFIL = 0;  //唤醒
C1CFG2bits.PRSEG = 0; //传播时间段，实际值+1
C1CFG2bits.SEG1PH = 1; //相位缓冲段1段，实际值+1
C1CFG2bits.SEG2PH = 1; //相位缓冲段2段，实际值+1
C1CFG2bits.SEG2PHTS = 1; //相位缓冲段2时间选择位，1-自由编程
C1CFG1bits.SJW = 0; //同步段	，实际值+1 
C1CFG1bits.BRP = SYSTEM_FOSC/2 /2/(C1CFG1bits.SJW+1+C1CFG2bits.PRSEG+1+C1CFG2bits.SEG1PH+1+C1CFG2bits.SEG2PH+1)/baudrate -1; //波特率预分频
C1CFG2bits.SAM = 0;// = 0x3BE;	//WAKFIL disabled; SEG2PHTS Freely programmable; SEG2PH 4 x TQ; SEG1PH 8 x TQ; PRSEG 7 x TQ; SAM Once at the sample point; 
 *******/

#include "can.h"
#include "../system/system.h"
#include "../dma/dma.h"


#define ECAN1_TX_DMA_CHANNEL DMA_CHANNEL_1
#define ECAN1_RX_DMA_CHANNEL DMA_CHANNEL_0

/* Valid options are 4, 6, 8, 12, 16, 24, or 32. */
#define CAN1_MESSAGE_BUFFERS         32
              
#define CAN1_FIFO_STARTING_BUFFER    0x8

#define CAN1_TX_BUFFER_COUNT 8

/******************************************************************************/

/******************************************************************************/
/* Private type definitions                                               */
/******************************************************************************/
typedef struct __attribute__((packed))
{
    unsigned priority                   :2;
    unsigned remote_transmit_enable     :1;
    unsigned send_request               :1;
    unsigned error                      :1;
    unsigned lost_arbitration           :1;
    unsigned message_aborted            :1;
    unsigned transmit_enabled           :1;
} CAN1_TX_CONTROLS;

/******************************************************************************/
/* Private variable definitions                                               */
/******************************************************************************/
/* This alignment is required because of the DMA's peripheral indirect 
 * addressing mode. */
static unsigned int ecan1msgBuf [CAN1_MESSAGE_BUFFERS][8] __attribute__((aligned(32 * 8 * 2)));

/******************************************************************************/
/* Private function prototypes                                                */
/******************************************************************************/
static void ECAN1_DMACopy(uint8_t buffer_number, uCAN1_MSG *message);
static void ECAN1_MessageToBuffer(uint16_t* buffer, uCAN1_MSG* message);

void ECAN1_TransmitEnable();
void ECAN1_ReceiveEnable();
bool ECAN1_isBusOff();
bool ECAN1_isRXErrorPassive();
bool ECAN1_isTXErrorPassive();
uint8_t ECAN1_messagesInBuffer();
void ECAN1_sleep();
bool ECAN1_Receive_m(uCAN1_MSG *recCanMsg);

/**
  Section: ECAN1 APIs
*****************************************************************************************/

void ECAN1_Initialize_g(void)
{
    // Disable interrupts before the Initialization
    IEC2bits.C1IE = 0;
    C1INTE = 0;

    // set the CAN{instance}_initialize module to the options selected in the User Interface

    /* put the module in configuration mode */
    C1CTRL1bits.REQOP = CAN1_CONFIGURATION_MODE;
    while(C1CTRL1bits.OPMODE != CAN1_CONFIGURATION_MODE);

    /* Set up the baud rate*/	
//    C1CFG1 = 0x03;	//BRP TQ = (2 x 4)/FCAN; SJW 1 x TQ; 
//    C1CFG2 = 0x3BE;	//WAKFIL disabled; SEG2PHTS Freely programmable; SEG2PH 4 x TQ; SEG1PH 8 x TQ; PRSEG 7 x TQ; SAM Once at the sample point; 
    // C1CFG1bits.BRP = Fosc/2 /2/(C1CFG1bits.SJW+1+C1CFG2bits.PRSEG+1+C1CFG2bits.SEG1PH+1+C1CFG2bits.SEG2PH+1) -1
    // 限制：
    // 1、同步段+传播时间段+相位缓冲段1+相位缓冲段2 在8TQ到15TQ之间，包括边界值
    // 2、传播时间段+相位缓冲段1 >= 相位缓冲段2
    // 3、相位缓冲段2 > 同步段
    C1CFG2bits.WAKFIL = 0;  //唤醒
    C1CFG2bits.PRSEG = 6; //传播时间段，实际值+1
    C1CFG2bits.SEG1PH = 7; //相位缓冲段1段，实际值+1
    C1CFG2bits.SEG2PH = 3; //相位缓冲段2段，实际值+1
    C1CFG2bits.SEG2PHTS = 1; //相位缓冲段2时间选择位，1-自由编程
    C1CFG1bits.SJW = 0; //同步段	，实际值+1 
    C1CFG1bits.BRP = 3;//SYSTEM_FOSC/2 /2/(C1CFG1bits.SJW+1+C1CFG2bits.PRSEG+1+C1CFG2bits.SEG1PH+1+C1CFG2bits.SEG2PH+1)/250000 -1; //波特率预分频
    C1CFG2bits.SAM = 0;// = 0x3BE;	//WAKFIL disabled; SEG2PHTS Freely programmable; SEG2PH 4 x TQ; SEG1PH 8 x TQ; PRSEG 7 x TQ; SAM Once at the sample point; 

//    C1CFG1 = 0x03;	//BRP TQ = (2 x 4)/FCAN; SJW 1 x TQ; 
//    C1CFG2 = 0x3BE;	//WAKFIL disabled; SEG2PHTS Freely programmable; SEG2PH 4 x TQ; SEG1PH 8 x TQ; PRSEG 7 x TQ; SAM Once at the sample point; 
    
    C1FCTRL = 0xC008;	//FSA Receive Buffer RB8; DMABS 32; 
    C1FEN1 = 0x01;	//FLTEN8 disabled; FLTEN7 disabled; FLTEN9 disabled; FLTEN0 enabled; FLTEN2 disabled; FLTEN10 disabled; FLTEN1 disabled; FLTEN11 disabled; FLTEN4 disabled; FLTEN3 disabled; FLTEN6 disabled; FLTEN5 disabled; FLTEN12 disabled; FLTEN13 disabled; FLTEN14 disabled; FLTEN15 disabled; 
    C1CTRL1 = 0x00;	//CANCKS FOSC/2; CSIDL disabled; ABAT disabled; REQOP Sets Normal Operation Mode; WIN Uses buffer window; CANCAP disabled; 

    /* Filter configuration */
    /* enable window to access the filter configuration registers */
    /* use filter window*/
    C1CTRL1bits.WIN=1;
	   
    /* select acceptance masks for filters */
    C1FMSKSEL1bits.F0MSK = 0x0; //Select Mask 0 for Filter 0

    /* Configure the masks */
    C1RXM0SIDbits.SID = 0x7f7; 
    C1RXM1SIDbits.SID = 0x0; 
    C1RXM2SIDbits.SID = 0x0; 

    C1RXM0SIDbits.EID = 0x3; 
    C1RXM1SIDbits.EID = 0x0; 
    C1RXM2SIDbits.EID = 0x0; 
     
    C1RXM0EID = 0xFFFF;     	
    C1RXM1EID = 0x00;     	
    C1RXM2EID = 0x00;     	

    C1RXM0SIDbits.MIDE = 0x0; 
    C1RXM1SIDbits.MIDE = 0x0; 
    C1RXM2SIDbits.MIDE = 0x0; 
    
    /* Configure the filters */
    C1RXF0SIDbits.SID = 0x318; 

    C1RXF0SIDbits.EID = 0x1; 
    
    C1RXF0EID = 0xD5D3; 

    C1RXF0SIDbits.EXIDE = 0x0; 

    /* FIFO Mode */
    C1BUFPNT1bits.F0BP = 0xf; //Filter 0 uses FIFO

    /* clear window bit to access ECAN control registers */
    C1CTRL1bits.WIN=0;    

    /* ECAN1, Buffer 0 is a Transmit Buffer */
    C1TR01CONbits.TXEN0 = 0x1; // Buffer 0 is a Transmit Buffer 
    C1TR01CONbits.TXEN1 = 0x1; // Buffer 1 is a Transmit Buffer 
    C1TR23CONbits.TXEN2 = 0x1; // Buffer 2 is a Transmit Buffer 
    C1TR23CONbits.TXEN3 = 0x1; // Buffer 3 is a Transmit Buffer 
    C1TR45CONbits.TXEN4 = 0x1; // Buffer 4 is a Transmit Buffer 
    C1TR45CONbits.TXEN5 = 0x1; // Buffer 5 is a Transmit Buffer 
    C1TR67CONbits.TXEN6 = 0x1; // Buffer 6 is a Transmit Buffer 
    C1TR67CONbits.TXEN7 = 0x1; // Buffer 7 is a Transmit Buffer 

    C1TR01CONbits.TX0PRI = 0x0; // Message Buffer 0 Priority Level
    C1TR01CONbits.TX1PRI = 0x0; // Message Buffer 1 Priority Level
    C1TR23CONbits.TX2PRI = 0x0; // Message Buffer 2 Priority Level
    C1TR23CONbits.TX3PRI = 0x0; // Message Buffer 3 Priority Level
    C1TR45CONbits.TX4PRI = 0x0; // Message Buffer 4 Priority Level
    C1TR45CONbits.TX5PRI = 0x0; // Message Buffer 5 Priority Level
    C1TR67CONbits.TX6PRI = 0x0; // Message Buffer 6 Priority Level
    C1TR67CONbits.TX7PRI = 0x0; // Message Buffer 7 Priority Level

    /* clear the buffer and overflow flags */   
    C1RXFUL1 = 0x0000;
    C1RXFUL2 = 0x0000;
    C1RXOVF1 = 0x0000;
    C1RXOVF2 = 0x0000;	

    /* configure the device to interrupt on the receive buffer full flag */
    /* clear the buffer full flags */ 	
    C1INTFbits.RBIF = 0;  

    /* put the module in normal mode */
    C1CTRL1bits.REQOP = CAN1_NORMAL_OPERATION_MODE;
    while(C1CTRL1bits.OPMODE != CAN1_NORMAL_OPERATION_MODE);

    ECAN1_TransmitEnable();
    ECAN1_ReceiveEnable();
}


void ECAN1_TransmitEnable()
{
    /* setup channel 0 for peripheral indirect addressing mode 
    normal operation, word operation and select as Tx to peripheral */

    /* DMA_PeripheralIrqNumberSet and DMA_TransferCountSet would be done in the 
    DMA */
    
    /* setup the address of the peripheral ECAN1 (C1TXD) */ 
    DMA_PeripheralAddressSet(ECAN1_TX_DMA_CHANNEL, &C1TXD);

    /* DPSRAM start address offset value */ 
    /* DPSRAM start address offset value */ 
    DMA_StartAddressASet(ECAN1_TX_DMA_CHANNEL, __builtin_dmaoffset(&ecan1msgBuf));

    /* enable the channel */
    DMA_ChannelEnable(ECAN1_TX_DMA_CHANNEL);
}

void ECAN1_ReceiveEnable()
{
    /* setup DMA channel for peripheral indirect addressing mode 
    normal operation, word operation and select as Rx to peripheral */

    /* setup the address of the peripheral ECAN1 (C1RXD) */     
    /* DMA_TransferCountSet and DMA_PeripheralIrqNumberSet would be set in 
    the DMA_Initialize function */

    DMA_PeripheralAddressSet(ECAN1_RX_DMA_CHANNEL, &C1RXD);

    /* DPSRAM start address offset value */ 
    DMA_StartAddressASet(ECAN1_RX_DMA_CHANNEL, __builtin_dmaoffset(&ecan1msgBuf) );	  

    /* enable the channel */
    DMA_ChannelEnable(ECAN1_RX_DMA_CHANNEL);
}

bool ECAN1_Transmit_g(ECAN1_TX_PRIOIRTY priority, uCAN1_MSG *sendCanMsg) 
{
    CAN1_TX_CONTROLS * pTxControls = (CAN1_TX_CONTROLS*)&C1TR01CON;
    uint_fast8_t i;
    bool messageSent = false;

    for(i=0; i<CAN1_TX_BUFFER_COUNT; i++)
    {
        if(pTxControls->transmit_enabled == 1)
        {
            if (pTxControls->send_request == 0)
            {
                ECAN1_MessageToBuffer( &ecan1msgBuf[i][0], sendCanMsg );

                pTxControls->priority = priority;

                /* set the message for transmission */
                pTxControls->send_request = 1; 

                messageSent = true;
                break;
            }
        }

        pTxControls++;
    }

    return messageSent;
}

bool ECAN1_Receive_m(uCAN1_MSG *recCanMsg) 
{   
    uint_fast8_t currentBuffer;
    uint_fast8_t shiftAmount;
    bool messageReceived = false;
    uint16_t receptionFlags;

    if(C1INTFbits.RBOVIF == 1)
    {
        C1INTFbits.RBOVIF = 0;
        return messageReceived;
    }
    
    currentBuffer = C1FIFObits.FNRB;
    if( currentBuffer < 16)
    {
	receptionFlags = C1RXFUL1;
        shiftAmount = currentBuffer;
    }
    else
    {
        receptionFlags = C1RXFUL2;
        shiftAmount = currentBuffer - 16;
    }
    
    if (((receptionFlags >> shiftAmount ) & 0x1) == 0x1)
    {           
       ECAN1_DMACopy(currentBuffer, recCanMsg);

        if( currentBuffer < 16)
        {
            C1RXFUL1 &= ~(1 << shiftAmount);
        }
        else
        {
            C1RXFUL2 &= ~(1 << shiftAmount);
        }

        messageReceived = true;
    }
        
    return (messageReceived);
}


/******************************************************************************
*                                                                             
*    Function:		ECAN1_isBusOff
*    Description:       Checks whether the transmitter in Bus off state
*                                                                             
                                             
*    Return Value:      true - Transmitter in Bus Off state
*                       false - Transmitter not in Bus Off state                                                                              
******************************************************************************/
bool ECAN1_isBusOff() 
{
    return C1INTFbits.TXBO;	
}

/******************************************************************************
*                                                                             
*    Function:		ECAN1_isRXErrorPassive
*    Description:       Checks whether the receive in error passive state
*                                             
*    Return Value:      true - Receiver in Error Passive state
*                       false - Receiver not in Error Passive state                                                                              
******************************************************************************/
bool ECAN1_isRXErrorPassive()
{
    return C1INTFbits.RXBP;   
}

/******************************************************************************
*                                                                             
*    Function:		ECAN1_isTXErrorPassive
*    Description:       Checks whether the transmitter in error passive state                                                                          
*                                             
*    Return Value:      true - Transmitter in Error Passive state
*                       false - Transmitter not in Error Passive state                                                                              
******************************************************************************/
bool ECAN1_isTXErrorPassive()
{
    return (C1INTFbits.TXBP);
}

/******************************************************************************
*                                                                             
*    Function:		ECAN1_messagesInBuffer
*    Description:       returns the number of messages that are received                                                                           
*                                             
*    Return Value:      Number of message received
******************************************************************************/
uint8_t ECAN1_messagesInBuffer() 
{
    uint_fast8_t messageCount;
    uint_fast8_t currentBuffer;
    uint16_t receptionFlags;
   
    messageCount = 0;

#if (CAN1_FIFO_STARTING_BUFFER<16)
    /* Check any message in buffer 0 to buffer 15*/
    receptionFlags = C1RXFUL1;
    if (receptionFlags != 0) 
    {
        /* check whether a message is received */  
        for (currentBuffer=0 ; currentBuffer < 16; currentBuffer++)
        {
            if (((receptionFlags >> currentBuffer ) & 0x1) == 0x1)
            {
                messageCount++;
            }
        }
    }
#endif

    /* Check any message in buffer 16 to buffer 32*/
    receptionFlags = C1RXFUL2;
    if (receptionFlags != 0) 
    {
        /* check whether a message is received */  
        for (currentBuffer=0 ; currentBuffer < 16; currentBuffer++)
        {
            if (((receptionFlags >> currentBuffer ) & 0x1) == 0x1)
            {
                messageCount++;
            }
        }
    }
            
    return (messageCount);
}

/******************************************************************************
*                                                                             
*    Function:		ECAN1_sleep
*    Description:       Puts ECAN1 module in disable mode.
*                                                                       
******************************************************************************/
void ECAN1_sleep(void) {
    C1INTFbits.WAKIF = 0;
    C1INTEbits.WAKIE = 1;

    /* Enable ECAN1 Interrupt */
    IEC2bits.C1IE = 1;

    /* put the module in disable mode */
    C1CTRL1bits.REQOP=CAN1_DISABLE_MODE;
    while(C1CTRL1bits.OPMODE != CAN1_DISABLE_MODE);
    
    //Wake up from sleep should set the CAN module straight into Normal mode
}

/*******************************************************************************
 * PRIVATE FUNCTIONS
 ******************************************************************************/

/******************************************************************************
*                                                                             
*    Function:		ECAN1_DMACopy
*    Description:       moves the message from the DMA memory to RAM
*                                                                             
*    Arguments:		*message: a pointer to the message structure in RAM 
*			that will store the message. 
*	                                                                 
*                                                                              
******************************************************************************/
static void ECAN1_DMACopy(uint8_t buffer_number, uCAN1_MSG *message)
{
    uint16_t ide=0;
    uint16_t rtr=0;
    uint32_t id=0;

    /* read word 0 to see the message type */
    ide=ecan1msgBuf[buffer_number][0] & 0x0001U;			

    /* check to see what type of message it is */
    /* message is standard identifier */
    if(ide==0U)
    {
        message->frame.id=(ecan1msgBuf[buffer_number][0] & 0x1FFCU) >> 2U;		
        message->frame.idType = CAN1_FRAME_STD;
        rtr=ecan1msgBuf[buffer_number][0] & 0x0002U;
    }
    /* message is extended identifier */
    else
    {
        id=ecan1msgBuf[buffer_number][0] & 0x1FFCU;		
        message->frame.id = id << 16U;
        message->frame.id += ( ((uint32_t)ecan1msgBuf[buffer_number][1] & (uint32_t)0x0FFF) << 6U );
        message->frame.id += ( ((uint32_t)ecan1msgBuf[buffer_number][2] & (uint32_t)0xFC00U) >> 10U );		
        message->frame.idType = CAN1_FRAME_EXT;
        rtr=ecan1msgBuf[buffer_number][2] & 0x0200;
    }
    /* check to see what type of message it is */
    /* RTR message */
    if(rtr != 0U)
    {
        /* to be defined ?*/
        message->frame.msgtype = CAN1_MSG_RTR;	
    }
    /* normal message */
    else
    {
        message->frame.msgtype = CAN1_MSG_DATA;
        message->frame.data0 =(unsigned char)ecan1msgBuf[buffer_number][3];
        message->frame.data1 =(unsigned char)((ecan1msgBuf[buffer_number][3] & 0xFF00U) >> 8U);
        message->frame.data2 =(unsigned char)ecan1msgBuf[buffer_number][4];
        message->frame.data3 =(unsigned char)((ecan1msgBuf[buffer_number][4] & 0xFF00U) >> 8U);
        message->frame.data4 =(unsigned char)ecan1msgBuf[buffer_number][5];
        message->frame.data5 =(unsigned char)((ecan1msgBuf[buffer_number][5] & 0xFF00U) >> 8U);
        message->frame.data6 =(unsigned char)ecan1msgBuf[buffer_number][6];
        message->frame.data7 =(unsigned char)((ecan1msgBuf[buffer_number][6] & 0xFF00U) >> 8U);
        message->frame.dlc =(unsigned char)(ecan1msgBuf[buffer_number][2] & 0x000FU);
    }
}

/******************************************************************************
*                                                                             
*    Function:		ECAN1_MessageToBuffer
*    Description:       This function takes the input message, reformats it, 
*                       and copies it to the specified CAN module buffer
*                                                                             
*    Arguments:		*buffer: a pointer to the buffer where the message 
*                       would be stored 
*                       *message: pointer to the input message that is received
*                       by the CAN module 	                                                                 
*                                                                              
******************************************************************************/
static void ECAN1_MessageToBuffer(uint16_t* buffer, uCAN1_MSG* message)
{   
    if(message->frame.idType == CAN1_FRAME_STD)
    {
        buffer[0]= (message->frame.id & 0x000007FF) << 2;
        buffer[1]= 0;
        buffer[2]= message->frame.dlc & 0x0F;
    }
    else
    {
        buffer[0]= ( ( (uint16_t)(message->frame.id >> 16 ) & 0x1FFC ) ) | 0b1;
        buffer[1]= (uint16_t)(message->frame.id >> 6) & 0x0FFF;
        buffer[2]= (message->frame.dlc & 0x0F) + ( (uint16_t)(message->frame.id << 10) & 0xFC00);
    }

    buffer[3]= ((message->frame.data1)<<8) + message->frame.data0;
    buffer[4]= ((message->frame.data3)<<8) + message->frame.data2;
    buffer[5]= ((message->frame.data5)<<8) + message->frame.data4;
    buffer[6]= ((message->frame.data7)<<8) + message->frame.data6;
}

//在while循环中接收CAN数据
bool ECAN1_ReceiveCanMsg_g(uCAN1_MSG *recMsg)
{
    bool b=false;
    if(C1INTFbits.RBIF==1)
    {
        b= ECAN1_Receive_m(recMsg);
        C1INTFbits.RBIF = 0; 
    }
    
    return b;
}